package epoch.game.core.distr.service;

import java.lang.reflect.Method;
import java.util.HashMap;

import epoch.game.core.distr.Node;
import epoch.game.core.distr.NodeMessage;
import epoch.game.core.distr.ThreadContext;
import epoch.game.core.distr.call.Call;
import epoch.game.core.distr.call.CallContext;
import epoch.game.core.function.IFunc1;
import epoch.game.core.function.IFunc2;
import epoch.game.core.message.SysMessageIds;
import epoch.game.core.serialize.StreamWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 服务代理[暂时未使用，目前使用代码生成代理方式]
 * @author will
 * @date 2016年4月5日 下午3:20:17
 */
public final class ServiceProxy<T> {
	
	private static boolean GEN_PROXY=false;
	
	public static HashMap<Class<?>,AbstractProxy> proxyMap;
	
	static{
		if(GEN_PROXY){
			proxyMap = new HashMap<Class<?>, AbstractProxy>();
		}
	}
	
	private T service;
	
	/**
	 * 创建代理类
	 * @param nodeId
	 * @param serviceId
	 * @return
	 */
	public static <S> ServiceProxy<S> createProxy(Class<S> serviceClass){
		ServiceProxy<S> proxy = new ServiceProxy<S>();
//		int remoteNodeId = locator.getServiceNodeId(serviceClass);
//		ThreadContext context = ThreadContext.getCurrent();
//		if (remoteNodeId == context.getNode().getId()) {
//			// 本地服务直接调用
//			proxy.local = true;
//			proxy.service = locator.getService(serviceClass);
//		} else {			
			proxy.service = createService(serviceClass);
//		}
		return proxy;
	}
	
	/**
	 * 创建服务接口代理
	 * @param serviceId
	 * @return
	 */
	public static <T> T createService(Class<T> serviceClass) {		
		int remoteNodeId = ServiceLocator.getServiceNodeId(serviceClass);
		ThreadContext context = ThreadContext.getCurrent();
		//动态代理，可以考虑代码生成代理类，在这个地方进行创建代理，返回即可
		Enhancer enhencer = new Enhancer();
		enhencer.setInterfaces(new Class[]{serviceClass});
		enhencer.setSuperclass(serviceClass);
		RpcMethodInterceptor methodInvoker = new RpcMethodInterceptor(serviceClass,context,remoteNodeId);
		enhencer.setCallback(methodInvoker);		
		@SuppressWarnings("unchecked")
		T service = (T) enhencer.create();
		
		return service;
	}

	
	/**
	 * 创建服务接口代理
	 * @param remoteNodeId
	 * @param serviceId
	 * @return
	 */
	public static <T> T createService(Class<T> serviceClass, int remoteNodeId) {
		ThreadContext context = ThreadContext.getCurrent();
		//动态代理，可以考虑代码生成代理类，在这个地方进行创建代理，返回即可
		Enhancer enhencer = new Enhancer();
		enhencer.setInterfaces(new Class[]{serviceClass});
		enhencer.setSuperclass(serviceClass);
		RpcMethodInterceptor methodInvoker = new RpcMethodInterceptor(serviceClass,context,remoteNodeId);
		enhencer.setCallback(methodInvoker);		
		@SuppressWarnings("unchecked")
		T service = (T) enhencer.create();
		return service;
	}

	/**
	 * RPC方法拦截器
	 * @author will
	 * @date 2016年4月12日 上午10:37:43
	 */
	private static class RpcMethodInterceptor implements MethodInterceptor{
		
		//线程上下文
		private ThreadContext threadContext;
		//远程节点id
		private int remoteNodeId;
		
		private Class<?> serviceClass;
		
		public RpcMethodInterceptor(Class<?> servClass, ThreadContext threadContext, int remoteNodeId){
			this.serviceClass = servClass;
			this.remoteNodeId = remoteNodeId;
			this.threadContext = threadContext;
		}
		
		@Override
		public Object intercept(Object targetObject, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
			Node node = threadContext.getNode();
			IService service = null;
			boolean local = false;
			if (remoteNodeId == threadContext.getNode().getId()) {
				// 本地服务直接调用
				service = ServiceLocator.getService(serviceClass);
				local = true;
			}else{
				service = (IService)targetObject;
			}			
			Call call = new Call();
			call.fromNodeId = node.getId();
			call.fromPortId = threadContext.getId();
			//如何知道是否注册回调？
			call.methodParam = params;
			call.callFlag = 0;
			call.serviceId=ServiceLocator.getServiceId(serviceClass);
//			call.methodKey=service.getMethodKey(method);
			call.callbackId = threadContext.currentCallbackId;
			//清除回调
			threadContext.currentCallbackId=0;
			if (local) {
				// 本地服务直接调用
				service.doCall(call);
			}else{
				StreamWriter writer = new StreamWriter();
				call.writeTo(writer);
				byte[] calldata = writer.array();
				NodeMessage nodeMsg = new NodeMessage();
				nodeMsg.setId(SysMessageIds.rpc_call);
				nodeMsg.setMsgData(calldata);
				node.sendNodeMsg(remoteNodeId, nodeMsg);
			}
			return null;
		}
	}



	public T getService() {
		return service;
	}

	
//	/**
//	 * 监听回调
//	 * 
//	 * @param callback
//	 *            回调方法
//	 * @param param
//	 *            参数
//	 */
//	public void listenResult(Object callback, Param param) {
//		// 下一个服务操作需要告诉调用的服务是有回调
//		ThreadContext context = ThreadContext.getCurrent();
//		context.listenResult(callback, param);
//	}

//	public void setCallFlag(int callFlag) {
//		ThreadContext context = ThreadContext.getCurrent();
//		context.callFlag = callFlag;
//	}

	public <P> void listenResult(IFunc1<P> callback, CallContext context) {
		ThreadContext.listenResult(callback, context);
	}
	
	public <R> void listenResult(IFunc2<CallContext, R> callback, CallContext context) {
		ThreadContext.listenResult(callback, context);
	}
	
	public <R> void listenResult(IFunc1<R> callback, CallContext context, boolean handleTimeOut) {
		ThreadContext.listenResult(callback, context, handleTimeOut);
	}

	public <R> void listenResult(IFunc2<CallContext, R> callback, CallContext context, boolean handleTimeOut) {
		ThreadContext.listenResult(callback, context, handleTimeOut);
	}
}
